import {
  CallHandler,
  ExecutionContext,
  HttpException,
  HttpStatus,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { AND, MIX_AND, OR } from 'src/decorator/reqtype.decorator';
import { AuthItem } from 'src/global-type';
import { getIp } from 'src/system-log/utils';
import { SystemUserService } from 'src/system-user/system-user.service';
import FileLogger from 'src/utils/file-logger';
import { aesDecode } from 'src/utils/handle-crypto';

type ArgeTypes =
  | [string]
  | [string, string]
  | [string, string, symbol]
  | [string, string, string, string, symbol];

@Injectable()
export class OpenApiInterceptor implements NestInterceptor {
  private readonly logger = new FileLogger(OpenApiInterceptor.name);
  constructor(
    private readonly systemUserService: SystemUserService,
    private reflector: Reflector,
  ) {}
  async intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Promise<Observable<any>> {
    try {
      const request = context.switchToHttp().getRequest();
      const reqPath = request.route.path;
      const { token, timestamp } = request.headers;
      const decStr = aesDecode(token, reqPath, timestamp);
      const [account, encPass] = decStr.split(':');
      const currUser = await this.systemUserService.findOneSystemUser({
        account,
      });
      if (!currUser)
        throw new HttpException(
          {
            code: -1,
            message: '未查找到当前用户信息',
            data: null,
          },
          HttpStatus.FORBIDDEN,
        );
      if (currUser.password !== encPass)
        throw new HttpException(
          {
            code: -1,
            message: '用户信息校验失败',
            data: null,
          },
          HttpStatus.OK,
        );
      if (!currUser.auth)
        throw new HttpException(
          {
            code: -1,
            message: '无法获取当前用户权限，请联系系统管理员进行确认',
            data: null,
          },
          HttpStatus.OK,
        );
      const auth = await this.systemUserService.findOneAuth({
        _id: currUser.auth,
      });
      const ip = getIp(request);
      request.userInfo = Object.assign(currUser.toObject(), { auth, ip });
      const PRIM_REQTYPE = this.reflector.get<ArgeTypes>(
        'reqtype',
        context.getHandler(),
      );
      if (PRIM_REQTYPE.length < 1) {
        throw new HttpException(
          {
            code: -1,
            message: '权限解析错误, 请联系管理员进行处理',
            data: null,
          },
          HttpStatus.OK,
        );
      }
      if (PRIM_REQTYPE.length === 1) {
        if (PRIM_REQTYPE[0] === AuthItem.READ) return next.handle();
        const ifRead = auth[PRIM_REQTYPE[0]].includes(AuthItem.READ);
        if (ifRead) return next.handle();
        throw new HttpException(
          {
            code: -1,
            message: '没有相关操作权限，请联系管理员进行处理',
            data: null,
          },
          HttpStatus.OK,
        );
      } else if (PRIM_REQTYPE.length === 2) {
        const [moduletype, reqtype] = PRIM_REQTYPE;
        // 首先验证是否具备读取权限
        if (reqtype !== AuthItem.READ) {
          const ifRead = auth[moduletype].includes(AuthItem.READ);
          if (!ifRead) {
            throw new HttpException(
              {
                code: -1,
                message:
                  '无法在不具备读取权限时进行其他操作，请联系管理员进行处理',
                data: null,
              },
              HttpStatus.OK,
            );
          }
        }
        if (auth[moduletype].includes(reqtype)) return next.handle();
        throw new HttpException(
          {
            code: -1,
            message: '没有相关操作权限，请联系管理员进行处理',
            data: null,
          },
          HttpStatus.OK,
        );
      } else if (PRIM_REQTYPE.length === 3) {
        const ifRead = auth[PRIM_REQTYPE[0]].includes(AuthItem.READ);
        if (!ifRead) {
          throw new HttpException(
            {
              code: -1,
              message:
                '无法在不具备读取权限时进行其他操作，请联系管理员进行处理',
              data: null,
            },
            HttpStatus.OK,
          );
        }
        const [moduletype, reqtype, FLAG] = PRIM_REQTYPE;
        if (FLAG === OR) {
          // 或逻辑
          const authsArr =
            typeof reqtype === 'string' ? reqtype.split('|') : [];
          const tempFlag = auth[moduletype].some((item) =>
            authsArr.includes(item),
          );
          if (tempFlag) return next.handle();
          throw new HttpException(
            {
              code: -1,
              message: '没有相关操作权限，请联系管理员进行处理',
              data: null,
            },
            HttpStatus.OK,
          );
        } else if (FLAG === AND) {
          // 与逻辑
          const authsArr =
            typeof reqtype === 'string' ? reqtype.split('&') : [];
          const tempFlag = auth[moduletype].some(
            (item) => !authsArr.includes(item),
          );
          if (tempFlag)
            throw new HttpException(
              {
                code: -1,
                message: '没有相关操作权限，请联系管理员进行处理',
                data: null,
              },
              HttpStatus.OK,
            );
          return next.handle();
        } else {
          throw new HttpException(
            {
              code: -1,
              message: '错误的模式标识符，请联系管理员进行处理',
              data: null,
            },
            HttpStatus.OK,
          );
        }
      } else if (PRIM_REQTYPE.length === 5) {
        const [moduletype1, reqtype1, moduletype2, reqtype2, FLAG] =
          PRIM_REQTYPE;
        if (FLAG !== MIX_AND)
          throw new HttpException(
            {
              code: -1,
              message: '错误的参数数量，请联系管理员进行处理',
              data: null,
            },
            HttpStatus.OK,
          );
        if (
          !auth[moduletype1].includes(AuthItem.READ) ||
          !auth[moduletype2].includes(AuthItem.READ)
        )
          throw new HttpException(
            {
              code: -1,
              message:
                '无法在不具备读取权限时进行其他操作，请联系管理员进行处理',
              data: null,
            },
            HttpStatus.OK,
          );
        if (
          auth[moduletype1].includes(reqtype1) &&
          auth[moduletype2].includes(reqtype2)
        )
          return next.handle();
        throw new HttpException(
          {
            code: -1,
            message: '没有相关操作权限，请联系管理员进行处理',
            data: null,
          },
          HttpStatus.OK,
        );
      } else {
        throw new HttpException(
          {
            code: -1,
            message: '错误的参数数量，请联系管理员进行处理',
            data: null,
          },
          HttpStatus.OK,
        );
      }
    } catch (err) {
      this.logger.printError(this.intercept.name, err);
      if (err.response) {
        throw new HttpException(err.response, err.status);
      } else {
        throw new HttpException(
          {
            code: -1,
            message: String(err),
            data: null,
          },
          HttpStatus.OK,
        );
      }
    }
    return next.handle();
  }
}
